package com.dd.cloud.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * @Description:
 * @Author: czg
 * @Date: 2022/12/1 15:15
 * @Version: 1.0.0
 */
@Slf4j
public class HttpRequestUtils {
    private static final String CHARSET = "UTF-8";

    private static final RequestConfig defaultRequestConfig = RequestConfig.custom()
            //设置等待数据超时时间
            .setSocketTimeout(30000)
            //设置连接超时时间
            .setConnectTimeout(30000)
            //设置从连接池获取连接的等待超时时间
            .setConnectionRequestTimeout(30000)
            //.setStaleConnectionCheckEnabled(true)
            .build();

    /**
     * 发送get请求，url带参数
     *
     * @param urlWithParams 带参数的请求路径
     * @return 请求响应结果
     * @throws IOException
     */
    public static String get(String urlWithParams) throws IOException {
        log.info("请求地址:{}", urlWithParams);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet(urlWithParams);
        CloseableHttpResponse response = httpClient.execute(httpget);
        HttpEntity entity = response.getEntity();
        String result = EntityUtils.toString(entity, CHARSET);
        httpget.releaseConnection();
        release(response, httpClient);
        return result;
    }

    /**
     * 发送get请求，url带参数
     *
     * @param urlWithParams 带参数的请求路径
     * @param headers       请求头
     * @return 请求响应结果
     * @throws IOException
     */
    public static String get(String urlWithParams, Map<String, String> headers) throws IOException {
        log.info("请求地址:{}", urlWithParams);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpget = new HttpGet(urlWithParams);
        headers.forEach(httpget::setHeader);
        CloseableHttpResponse response = httpClient.execute(httpget);
        HttpEntity entity = response.getEntity();
        String result = EntityUtils.toString(entity, CHARSET);
        httpget.releaseConnection();
        release(response, httpClient);
        return result;
    }


    /**
     * post 请求,接收参数为xml格式
     * contentType 为:text/xml; charset=utf-8
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String postWithXml(String url, String params) throws IOException {
        String contentType = "text/xml; charset=utf-8";
        return post(url, params, contentType);
    }

    /**
     * post 请求,接收参数为json格式
     * contentType 为:application/json; charset=utf-8
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String postWithJson(String url, String params) throws IOException {
        String contentType = "application/json; charset=utf-8";
        return post(url, params, contentType);
    }

    /**
     * post 请求
     *
     * @param url         请求地址
     * @param params      请求参数
     * @param contentType 请求内容类型 如：text/xml; charset=utf-8
     * @return 请求的返回结果
     * @throws IOException
     */
    public static String post(String url, String params, String contentType) throws IOException {
        log.info("请求地址:{}", url);
        String result;
        HttpPost httpPost = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = HttpClientBuilder.create().setDefaultRequestConfig(defaultRequestConfig).build();
            httpPost = new HttpPost(url);
            httpPost.addHeader("content-type", contentType);

            // 设置参数
            StringEntity se = new StringEntity(params, CHARSET);
            httpPost.setEntity(se);

            // result of response
            response = httpClient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity(), CHARSET);
        } finally {
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
            release(response, httpClient);
        }

        return result;
    }

    /**
     * post 请求
     *
     * @param url     请求地址
     * @param params  请求参数
     * @param headers 请求头内容
     * @return 请求的返回结果
     * @throws IOException
     */
    public static String post(String url, String params, Map<String, String> headers) throws IOException {
        log.info("请求地址:{}", url);
        String result;
        HttpPost httpPost = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = null;
        try {
            httpClient = HttpClientBuilder.create().setDefaultRequestConfig(defaultRequestConfig).build();
            httpPost = new HttpPost(url);
            for (String item : headers.keySet()) {
                httpPost.addHeader(item, headers.get(item));
            }

            // 设置参数
            StringEntity se = new StringEntity(params, CHARSET);
            httpPost.setEntity(se);

            // result of response
            response = httpClient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity(), CHARSET);
        } finally {
            if (httpPost != null) {
                httpPost.releaseConnection();
            }
            release(response, httpClient);
        }

        return result;
    }


    /**
     * 发送post请求；带请求头和请求参数
     *
     * @param url    请求地址
     * @param params 请求参数集合
     * @return
     * @throws Exception
     */
    public static String post(String url, Map<String, String> params) throws IOException {
        String result;
        CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(defaultRequestConfig).build();
        HttpPost httpPost = new HttpPost(url);
        packageParam(params, httpPost);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity(), CHARSET);
        } finally {
            httpPost.releaseConnection();
            release(response, httpClient);
        }
        return result;
    }

    public static String post(String url, List<NameValuePair> params, String content_type, String charset) throws IOException {
        CloseableHttpClient httpclient = HttpClientBuilder.create().setDefaultRequestConfig(defaultRequestConfig).build();
        HttpPost httppost = new HttpPost(url);
        httppost.addHeader("Content-Type", content_type);
        httppost.setEntity(new UrlEncodedFormEntity(params, charset));
        CloseableHttpResponse response = httpclient.execute(httppost);
        HttpEntity entity = response.getEntity();
        String result = EntityUtils.toString(entity, charset);
        httppost.releaseConnection();
        return result;
    }


    /**
     * 封装请求参数
     *
     * @param params     参数集合
     * @param httpMethod 请求方法
     * @throws UnsupportedEncodingException
     */
    private static void packageParam(Map<String, String> params, HttpEntityEnclosingRequestBase httpMethod) throws UnsupportedEncodingException {
        if (params != null) {
            List<NameValuePair> nvps = new ArrayList<>();
            Set<Entry<String, String>> entrySet = params.entrySet();
            for (Entry<String, String> entry : entrySet) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            // 设置到请求的http对象中
            httpMethod.setEntity(new UrlEncodedFormEntity(nvps, CHARSET));
        }
    }

    /**
     * 释放资源
     *
     * @param httpResponse 响应流
     * @param httpClient   请求客户端
     * @throws IOException
     */
    private static void release(CloseableHttpResponse httpResponse, CloseableHttpClient httpClient) throws IOException {
        if (httpResponse != null) {
            httpResponse.close();
        }
        if (httpClient != null) {
            httpClient.close();
        }
    }

    /**
     * @param map      参数
     * @param encoding 编码方式
     * @param url      路径
     */
    public static String send(String url, Map<String, String> map, String encoding) throws Exception {
        String body = "";

        // 创建httpclient对象
        CloseableHttpClient client = HttpClients.createDefault();
        // 创建post方式请求对象
        HttpPost httpPost = new HttpPost(url);

        // 装填参数
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        if (map != null) {
            for (Entry<String, String> entry : map.entrySet()) {
                nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }
        // 设置参数到请求对象中
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));

        // 设置header信息
        // 指定报文头【Content-type】、【User-Agent】
        httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");

        // 执行请求操作，并拿到结果（同步阻塞）
        CloseableHttpResponse response = client.execute(httpPost);
        // 获取结果实体
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            // 按指定编码转换结果实体为String类型
            body = EntityUtils.toString(entity, encoding);
        }
        EntityUtils.consume(entity);
        // 释放链接
        response.close();
        return body;
    }

    /**
     * 符号转换
     * 去掉空格等
     *
     * @param xml
     * @return
     */
    public static String replaceEscapeSequence(String xml) {
        return xml.replaceAll("&gt;", ">").replaceAll("&lt;", "<").replaceAll("&quot;", "\"");
    }

    /**
     * @param xml
     * @return
     */
    public static String replaceEscapeSequenceFor(String xml) {
        return xml.replaceAll(">", "&gt;").replaceAll("<", "&lt;").replaceAll("\"", "&quot;");
    }


    /**
     * ============忽略证书
     */
    private static CloseableHttpClient buildSSLCloseableHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            // 信任所有
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        }).build();
        // ALLOW_ALL_HOSTNAME_VERIFIER:这个主机名验证器基本上是关闭主机名验证的,实现的是一个空操作，并且不会抛出javax.net.ssl.SSLException异常。

        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
//                new String[] { "TLSv1" }, null,
                NoopHostnameVerifier.INSTANCE);
        //  AllowAllHostnameVerifier.INSTANCE);
        return HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(defaultRequestConfig).build();
    }

}
